/*
echo server with wait to deal SIGCHLD.
使用 waitpid 处理 SIGCHLD 信号。
 当 fork 子进程时，必须捕获 SIGCHLD 信号并且使用 waitpid 来处理。
 当捕获信号时，必须处理被中断的系统调用。
**/

#include "str_echo.h"
#include "sigchldwait.h"
#include <define.h>
#include <error.h>
#include <wrapfunc.h>
#include <sockfunc.h>
#include <sysfunc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <signal.h>


int
main() {
	Signal(SIGCHLD, sig_chld_waitpid);

	struct sockaddr_in local_addr;
	memset(&local_addr, 0, sizeof(local_addr));
	local_addr.sin_family = AF_INET;
	local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	local_addr.sin_port = htons(SERV_PORT);

	int listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	Bind(listenfd, (struct sockaddr*)&local_addr, sizeof(local_addr));
	Listen(listenfd, LISTENQ);
	error_msg("wait for clients");

	struct sockaddr_in connaddr;
	socklen_t len;
	int connfd;
	while (1) {
		len = sizeof(connaddr);
		connfd = accept(listenfd, (struct sockaddr*)&connaddr, &len);
		if (connfd < 0) {
			if (errno == EINTR) {
				error_msg("accept is being interrupted");
				continue;
			} else {
				error_dump("fail to accept");
			}
		}

		error_msg("new connection fd:%d %s", connfd, sock_ntop((struct sockaddr*)&connaddr, len));

		if (Fork() == 0) { // child process
			Close(listenfd);
			str_echo(connfd);
			Close(connfd);
			return 0;
		}
		Close(connfd);
	}

	Close(listenfd);
	return 0;
}
